<?
/**
 * 
 * GPFAction 클래스 : action 플러그인 관리, trigger 수행
 *
 * @author	chongmyung.park (http://byfun.com)
 */

if (!defined("GPF")) exit; // 개별 페이지 접근 불가 

include_once GPF_PATH."/lib/gpf.Config.class.php";
include_once GPF_PATH."/lib/gpf.PluginAction.class.php";

class GPFAction extends GPFObject
{
	/**
	 *
	 * @var 싱글톤 인스턴스
	 */
	protected static $instance = NULL;

	/**
	 * 생성자
	 */
	protected function __construct() {		
		 parent::__construct('action');
		 $this->afterLoadPlugins();
	}

	/**
	 * Singleton
	 */
	public static function getInstance() {
		if(!isset(self::$instance)) {
			self::$instance = new GPFAction();
		}
		return self::$instance;
	}

	/**
	 * 
	 * 플러그인 정렬 및 시스템 액션 등록
	 * 이벤트 trigger 시에 플러그인 순서에 따라 실행됨
	 * 
	 */
	protected function afterLoadPlugins()
	{
		// 이벤트를 order 순으로 정렬
		foreach($this->plugins as $k=>$v) {
			$this->plugins[$k] = $this->_subval_asort($this->plugins[$k], 'order');
		}		
		// 시스템 액션
		include_once GPF_PATH."/system/gpf.actions.php";
		$p = new GPFSystemPlugin();
		$p->regist($this);
	}

	/**
	 * 
	 * 액션 추가
	 *
	 * @param string $event 이벤트명
	 * @param obj $obj {@link GPFPlugin} 객체
	 * @param string $handler $obj 내에 구현된 이벤트 핸들러
	 */
	public function addAction($event, $obj, $handler)
	{
		if(!is_a($obj, "GPFActionPlugin")) gpf_die("GPFAction 에는 GPFActionPlugin 클래스를 상속한 인스턴스만 사용가능합니다.");
		$id = $obj->id;

		$filter_file = $obj->getDataPath('action')."/filter.php";
		$filter = null;
		if($obj->use_filter && file_exists($filter_file))
		{
			include $filter_file;		
			$filter = unserialize($filter);
		}

		if( !$this->check_filter($filter) ) return;

		$order = ($this->cfg->action_order[$id] ? $this->cfg->action_order[$id] : 99999);
		$this->plugins[strtoupper($event)][] = array("id"=>$id, "obj"=>$obj, "handler"=>$handler, "order"=>$order);
	}

	/**
	 *
	 * 플러그인을 register 해야할지 말아야할지 결정
	 * 사용할 플러그인이면 true, 아니면 false
	 */
	private function check_filter($filter)
	{
		if(!$filter) return true;
		return ($this->_check_apply($filter['apply']) && $this->_check_except($filter['except']));
	}

	/**
	 *
	 * 플러그인 사용을 허용할것이면 true, 아니면 false
	 */
	private function _check_apply($filter)
	{
		$bo_table = $GLOBALS['bo_table'];
		$member = $GLOBALS['member'];
		$empty_user = empty($filter['user']);
		$empty_board = empty($filter['board']);

		if( $empty_user && ( $empty_board ||  (!$empty_board && !$bo_table ) ) ) return true;

		if(!$empty_user) foreach($filter['user'] as $idx => $mb_id) if($member['mb_id'] == $mb_id) return true;
		if(!$empty_board) foreach($filter['board'] as $idx => $table) if($bo_table == $table) return true;
		
		return false;
	}

	/**
	 *
	 * 플러그인 사용을 허용할것이면 true, 아니면 false
	 */
	private function _check_except($filter)
	{
		$bo_table = $GLOBALS['bo_table'];
		$member = $GLOBALS['member'];
		$empty_user = empty($filter['user']);
		$empty_board = empty($filter['board']);
		
		if($empty_user && $empty_board) return true;

		if(!$empty_user) foreach($filter['user'] as $idx => $mb_id) if($member['mb_id'] == $mb_id) return false;
		if(!$empty_board) foreach($filter['board'] as $idx => $table) if($bo_table == $table) return false;
		
		return true;
	}

	/**
	 * 
	 * 이벤트 핸들러 실행
	 * 
	 * @param string $type 이벤트 타입 (WRITE_UPDATE, DELETE_TAIL, COMMENT_UPDATE 등..)
	 */
	public function trigger($type, $params=array()) {
		$returns = array();
		if(isset($this->plugins[$type]) && is_array($this->plugins[$type])) {
			foreach($this->plugins[$type] as $idx => $p) {
				$ret = $p['obj']->$p['handler']($type, $GLOBALS, $params);
				if(is_array($ret)) {
					foreach($ret as $k=>$v) { $returns[$k] = $GLOBALS[$k] = $v; }
				}
			}
		}
		return $returns;
	}

	/**
	 *
	 * 플러그인을 plugin_order 로 정렬하여 반환
	 */
	function _sort_plugins($plugins)
	{
		$tmp = array();
		foreach($plugins as $id => $p) 
		{
			$order = ( $this->cfg->action_order[$p->id] ? $this->cfg->action_order[$p->id] : 99999 );
			array_push($tmp, array('id'=>$id, 'plugin'=>$p, 'order'=>$order));
		}
		if(empty($tmp)) return array();
		$tmp = $this->_subval_asort($tmp, 'order');
		$res = array();
		foreach($tmp as $pi) $res[$pi['id']] = $pi['plugin'];
		return $res;
	}
}
?>